package com.egg.common.util;


import cn.hutool.core.date.SystemClock;
import cn.hutool.core.util.IdUtil;

import java.lang.management.ManagementFactory;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * id生成工具类
 *
 * @author east
 */
public class IdGenUtil {

    private static class SequenceNoUtils {
        /**
         * 时间搓格式化
         */
        private final DateTimeFormatter TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMdd");

        /**
         * 数字标识位数
         */
        private final long numberBitsMast = 26L;

        /**
         * 数据中心识位数
         */
        private final long dataCenterIdBits = 3L;

        /**
         * 机器标识位数
         */
        private final long workerIdBits = 11L;
        /**
         * 毫秒内自增位
         */
        private final long sequenceBits = numberBitsMast - dataCenterIdBits - workerIdBits;

        /**
         * 最大序列号
         */
        private final long sequenceMask = ~(-1L << sequenceBits);

        private final long workerIdShift = sequenceBits;

        private final long dataCenterIdShift = workerIdShift + workerIdBits;

        private long sequence = 0L;

        /**
         * 8个数字字符标识段左补齐
         */
        private final String numberFullLeft = "%08d";

        private long lastTimestamp = -1L;

        /**
         * 当前数据中心
         */
        private final long dataCenterId;

        /**
         * 当前机器节点
         */
        private final long workerId;

        private SequenceNoUtils() {
            // 最大数据中心数
            long maxDataCenterId = ~(-1L << dataCenterIdBits);
            this.dataCenterId = getDataCenterId(maxDataCenterId);

            // 最大机器节点数
            long maxWorkerId = ~(-1L << workerIdBits);
            this.workerId = getMaxWorkerId(dataCenterId, maxWorkerId);
        }

        /**
         * 单例模式-双重校验锁
         *
         * @return sq
         */
        private static SequenceNoUtils getSingleton() {
            return SequenceNoUtils.SingletonHolder.SINGLETON;
        }

        private static final class SingletonHolder {
            static final SequenceNoUtils SINGLETON = new SequenceNoUtils();
        }

        /**
         * next code
         *
         * @return code
         */
        private synchronized String nextCode() {
            long timestamp = timeGen();
            //闰秒
            if (timestamp < lastTimestamp) {
                long offset = lastTimestamp - timestamp;
                if (offset <= 5) {
                    try {
                        wait(offset << 1);
                        timestamp = timeGen();
                        if (timestamp < lastTimestamp) {
                            throw new RuntimeException(String.format("Clock moved backwards.  Refusing to generate id for %d milliseconds", offset));
                        }
                    } catch (Exception e) {
                        throw new RuntimeException(e);
                    }
                } else {
                    throw new RuntimeException(String.format("Clock moved backwards.  Refusing to generate id for %d milliseconds", offset));
                }
            }

            // 序列号自增
            sequence = (sequence + 1) & sequenceMask;
            if (sequence == 0) {
                // 同一毫秒的序列数已经达到最大
                timestamp = tilNextMillis(lastTimestamp);
            }

            lastTimestamp = timestamp;

            // 时间戳格式化 + (数据中心标识 | 机器标识部分 | 序列号部分)
            return TIME_FORMATTER.format(LocalDateTime.ofInstant(new Date(timestamp).toInstant(), ZoneId.systemDefault()))
                    // 左补齐
                    + String.format(numberFullLeft, ((dataCenterId << dataCenterIdShift)
                    | (workerId << workerIdShift)
                    | sequence));
        }

        /**
         * 数据标识id部分
         */
        private static long getDataCenterId(long maxDataCenterId) {
            long id = 0L;
            try {
                InetAddress ip = InetAddress.getLocalHost();
                NetworkInterface network = NetworkInterface.getByInetAddress(ip);
                if (network == null) {
                    id = 1L;
                } else {
                    byte[] mac = network.getHardwareAddress();
                    if (null != mac) {
                        id = ((0x000000FF & (long) mac[mac.length - 2]) | (0x0000FF00 & (((long) mac[mac.length - 1]) << 8))) >> 6;
                        id = id % (maxDataCenterId + 1);
                    }
                }
            } catch (Exception e) {

            }
            return id;
        }

        /**
         * 获取 maxWorkerId
         */
        private static long getMaxWorkerId(long maxDataCenterId, long maxWorkerId) {
            StringBuilder mpId = new StringBuilder();
            mpId.append(maxDataCenterId);
            String name = ManagementFactory.getRuntimeMXBean().getName();
            if (null != name && name.trim().length() > 0) {
                /*
                 * GET jvmPid
                 */
                mpId.append(name.split("@")[0]);
            }
            /*
             * MAC + PID 的 hashcode 获取16个低位
             */
            return (mpId.toString().hashCode() & 0xffff) % (maxWorkerId + 1);
        }

        /**
         * tilNextMillis
         *
         * @param lastTimestamp stamp
         * @return l
         */
        private long tilNextMillis(long lastTimestamp) {
            long timestamp = timeGen();
            while (timestamp <= lastTimestamp) {
                timestamp = timeGen();
            }
            return timestamp;
        }

        /**
         * 获取毫秒
         *
         * @return l
         */
        private long timeGen() {
            return SystemClock.now();
        }

        /**
         * 获取流水号
         *
         * @return code
         */
        public static String generateNo() {
            return getSingleton().nextCode();
        }

    }

    /**
     * 流水号
     */
    public static String serialId() {
        return SequenceNoUtils.generateNo();
    }

    /**
     * 字符串
     */
    public static String strId() {
        return IdUtil.objectId();
    }

    /**
     * 长整型
     */
    public static Long longId() {
        return IdUtil.getSnowflake().nextId();
    }


    public static void main(String[] args) throws InterruptedException, ExecutionException {
        int numThreads = 50;
        ExecutorService executor = Executors.newFixedThreadPool(numThreads);
        List<Future<String>> futures = new ArrayList<>();
        for (int i = 0; i < numThreads; i++) {
            Future<String> future = executor.submit(() -> {
                // 这里是你的线程要运行的代码
                return serialId();
            });
            futures.add(future);
        }

        executor.shutdown();
        // 等待所有线程执行完毕
        executor.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS);
        // 获取每个线程的运行结果并添加到结果列表中
        List<String> results = new ArrayList<>();
        for (Future<String> future : futures) {
            // 阻塞等待线程执行完成并获取结果
            results.add(future.get());
        }
        List<String> duplicates = results.stream()
                .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()))
                .entrySet().stream()
                .filter(entry -> entry.getValue() > 1)
                .map(Map.Entry::getKey)
                .collect(Collectors.toList());

        duplicates.forEach(System.out::println);


        System.out.println(strId());
        System.out.println(longId());
        System.out.println(serialId());
    }

}
